﻿
#include "picturetcpserver.h"
#include "ui_picturetcpserver.h"
#pragma execution_character_set("utf-8")

PictureTcpServer::PictureTcpServer(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::PictureTcpServer)
{
    ui->setupUi(this);
    ChangeEnable(false);
    this->setWindowIcon(QIcon(":/1.ico"));
    this->setWindowTitle("图片网络传输工具(服务器端)");
    m_count=0;
    m_basize=0;//初始化值0
    connect(&m_tcpServer,SIGNAL(newConnection()),this,SLOT(AcceptConnection()));
}

PictureTcpServer::~PictureTcpServer()
{
    delete ui;
}

 //接收数据带检验
void PictureTcpServer::ReadMyData()
{
    this->DelayTime(ui->txtTime->text().toInt());//延时等待数据处理完
    qDebug()<<"ReadMyData()接收数据带检验";
    if(m_pTcpServerConnection==nullptr){
        qDebug()<<"m_pTcpServerConnection==nullptr";
        return;
    }
    QDataStream in(m_pTcpServerConnection);
    in.setVersion(QDataStream::Qt_4_7);
    if (m_basize==0)
    {
        //判断接收的数据是否有两字节（文件大小信息）
        //如果有则保存到basize变量中，没有则返回，继续接收数据
        if (m_pTcpServerConnection->bytesAvailable()<(int)sizeof(quint16))
        {
            return;
        }
        in>>m_basize;
    }

    //如果没有得到全部数据，则返回继续接收数据
    if (m_pTcpServerConnection->bytesAvailable()<m_basize)
    {
        return;
    }

    /*将只读取剩余的数据部分，而不包括文件大小信息;
     *因为QDataStream类会按照先进先出（FIFO）的顺序读取数据流中的数据。
     *当调用in >> m_basize语句时，它会从数据流中读取指定类型和大小的数据，
     *并将其存储在变量m_basize中。而in >> m_message会继续从数据流中读取剩余的数据*/
    in>>m_message;                      //将接收到的数据存放到变量中

    ui->txtData->append(m_message);
    if (ui->ckbox->isChecked())
    {
        this->SaveData(m_message);
    }
    this->SaveImage(m_message);
    m_count+=1;
    qDebug()<<"m_count = "<<m_count;
    ui->labCount->setText(QString("提示:数据大小(%1) 图片张数(%2)").arg(QString::number(m_basize),QString::number(m_count)));
    m_basize=0;                         //重新归位0
    m_message.clear();                  //清空后重新存储

}

//保存图片
void PictureTcpServer::SaveImage(QByteArray ba)
{
    QString timeNow=QDateTime::currentDateTime().toString("yyyyMMddHHmmss");
    QString saveFileName=QCoreApplication::applicationDirPath()+tr("/imageto/%1.jpg").arg(timeNow);

    QDir folder(QCoreApplication::applicationDirPath());
    if (!folder.exists("imageto")) // 检查文件夹是否存在
    {
        if (!folder.mkpath("imageto")) // 创建文件夹并检查是否成功
        {
            // 创建文件夹失败，进行适当的错误处理
            return;
        }
    }

//    QString ss=QString::fromLatin1(ba.data(),ba.size());
//    QByteArray rc;
//    rc=QByteArray::fromBase64(ss.toLatin1());
//    QByteArray rdc=qUncompress(rc);

    QByteArray rdc=qUncompress(QByteArray::fromBase64(ba));         // 解压缩，得到解压后的二进制数据
    QImage img;
    img.loadFromData(rdc);                  // 从字节数组加载图像数据
    img.save(saveFileName);
}

//保存数据
void PictureTcpServer::SaveData(QByteArray ba)
{
    QString timeNow=QDateTime::currentDateTime().toString("yyyyMMddHHmmss");
    QString saveFileName=QCoreApplication::applicationDirPath()+tr("/imagedata/%1.txt").arg(timeNow);

    QDir folder(QCoreApplication::applicationDirPath());
    if (!folder.exists("imagedata")) // 检查文件夹是否存在
    {
        if (!folder.mkpath("imagedata")) // 创建文件夹并检查是否成功
        {
            // 创建文件夹失败，进行适当的错误处理
            return;
        }
    }

    QString str(ba);
    QFile file(saveFileName);
    if (file.open(QFile::WriteOnly| QIODevice::Truncate))
    {
        file.write(str.toLatin1());
        file.close();
    }
}

//延时等待功能
void PictureTcpServer::DelayTime(int ms)
{
    QTime t=QTime::currentTime().addMSecs(ms);//当前时间的基础上增加ms毫秒,得到一个目标时间点t
    while(QTime::currentTime()<t)
    {/*处理当前线程的事件队列，并等待最多100毫秒来接收新的事件。
      *处理所有类型的事件，包括定时器事件、绘图事件等
      *通过不断处理事件，可以确保程序在等待期间仍然能够响应其他事件，以避免程序无响应或阻塞*/
        QCoreApplication::processEvents(QEventLoop::AllEvents,100);
    }
}

void PictureTcpServer::ChangeEnable(bool isEnable)
{
    ui->btnStart->setEnabled(!isEnable);
    ui->btnSend->setEnabled(isEnable);
}

//开始监听
void PictureTcpServer::StartListen()
{
    if (!m_tcpServer.listen(QHostAddress::Any,ui->txtPort->text().toInt()))
    {
        ui->labCount->setText(tr("提示:发生错误(%1)").arg(m_tcpServer.errorString()));
        m_tcpServer.close();        //关闭TCP服务器，停止接受新的连接请求
        return;
    }
    ui->btnStart->setEnabled(false);
    ui->btnSend->setEnabled(false);
    ui->labCount->setText(tr("提示:正在监听"));
}

//建立连接
void PictureTcpServer::AcceptConnection()
{
    // 获取TCP服务器对象的下一个待处理的连接
    m_pTcpServerConnection=m_tcpServer.nextPendingConnection();
    connect(m_pTcpServerConnection,&QTcpSocket::readyRead,this,[=](){
        if (ui->rbtnPT->isChecked())    //普通方式接收数据
        {
            ReceiveData();
        }
        else                            //数据检验方式接收数据
        {
            ReadMyData();
        }
    });


    connect(m_pTcpServerConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(DisplayError(QAbstractSocket::SocketError)));

    connect(m_pTcpServerConnection,&QTcpSocket::disconnected,this,[=](){
        /*为了避免内存泄漏，调用deleteLater()函数以删除不再需要的QAbstractSocket对象;*/
        m_pTcpServerConnection->deleteLater();
        /*deleteLater()函数的作用是在事件循环处理完当前事件后删除对象，这样可以避免直接在槽函数中删除对象导致的问题，
         *而不会立即删除它。*/
    });

    m_tcpServer.close();            //关闭TCP服务器，停止接受新的连接请求
    ui->labCount->setText(tr("提示:客户端连接成功"));
    ui->btnSend->setEnabled(true);
}

//普通方式接收数据
void PictureTcpServer::ReceiveData()
{
    //this->DelayTime(ui->txtTime->text().toInt());
    QByteArray read=m_pTcpServerConnection->readAll();

    if (!read.isEmpty())
    {
        ui->txtData->append(QString::fromUtf8(read));
        if (ui->ckbox->isChecked())
        {
            this->SaveData(read);
        }
    }
}

void PictureTcpServer::DisplayError(QAbstractSocket::SocketError socketError)
{
    /* 调用close()函数后,QAbstractSocket对象进入QAbstractSocket::UnconnectedState状态，
     * 表示与客户端的连接已经断开，此时对象将无法进行进一步的通信或更新*/
    m_pTcpServerConnection->close();
    ui->labCount->setText(QString("提示:断开连接,错误(%1)").arg(m_pTcpServerConnection->errorString()));
    this->ChangeEnable(false);
}



void PictureTcpServer::on_btnStart_clicked()
{
    this->StartListen();
}


void PictureTcpServer::on_btnClear_clicked()
{
    ui->txtData->clear();
}


void PictureTcpServer::on_btnSend_clicked()
{
    m_pTcpServerConnection->write(ui->txt1->toPlainText().toUtf8());
    if (m_pTcpServerConnection->flush())
    {
        ui->labCount->setText(tr("提示:发送数据成功"));
    }
}


void PictureTcpServer::on_rbtnPT_toggled(bool checked)
{
    qDebug()<<"接收方式普通方式 使用="<<checked;
    if(checked)
    {
        if(m_pTcpServerConnection==nullptr)
            return;
        m_pTcpServerConnection->readAll(); // 读取并丢弃缓冲区中的数据

        qWarning() << "缓冲区已清空";

    }
}

